﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.ComponentModel;

// **** TODO (11/30): Upon checking/unchecking, call the function count_tile (can be done here or in RectLibrary) where the input is the togglebutton.Name
//                      The function count_tile takes Name, which is in _X,Y where we take the x (between _ and ,) and put it as fst in a tuple, and y as snd in that same tuple.
//                              (this might come in handy: let coords = input.[1..])
//                                  also find the index of the string where a character is: let commaIndex = coord.IndexOf 'x'
//                                      THUS: => let x = input.[1..(commaIndex-1)] and let y = input.[(commaIndex+1)..]
//                      Then we store this tuple (append it) in the tilesToBuild list. We can use a search to take it out if we need.
//                      After this, we can use the tuple list to build the inputBinMatrix.

namespace structurizer
{
	public partial class MainWindow : Window
	{
        public int opMode { get; set; }
        public Tuple<int, int>[] listTiles = { };
        public MainWindow()
		{
          
			this.InitializeComponent();
            Loaded += delegate
            {
                //tilingTools.conWindow.Show();
                // access ActualWidth and ActualHeight here
                // Insert code required on object creation below this point.
                double nActual = mainCanvas.ActualHeight;
                //MessageBox.Show("nActual = " + Convert.ToString(nActual));
                double mActual = mainCanvas.ActualWidth;
                //MessageBox.Show("mActual = " + Convert.ToString(mActual));
                int n = Convert.ToInt32(Math.Floor(nActual / 20)); // vertical, height
                //MessageBox.Show("n = " + Convert.ToString(n));
                int m = Convert.ToInt32(Math.Floor(mActual / 20)); // across, width
                //MessageBox.Show("m = " + Convert.ToString(m));

                //mainGrid.ShowGridLines = true;

                SolidColorBrush lbBrush = new SolidColorBrush();
                lbBrush.Color = Color.FromArgb(255, 127, 255, 212);
                SolidColorBrush wBrush = new SolidColorBrush();
                wBrush.Color = Colors.White;

                for (int c = 0; c < m; c++)
                {
                    // ** do we create the column here? with width = 20 (columns) and height 20 (rows)
                    mainGrid.ColumnDefinitions.Add(
                     new ColumnDefinition { Width = new GridLength(20) });
                }
                for (int d = 0; d < n; d++)
                {
                    mainGrid.RowDefinitions.Add(
                            new RowDefinition { Height = new GridLength(20) });
                }
                for (int i = 0; i < n; i++)
                {
                    for (int p = 0; p < m; p++)
                    {
                        int realHeight = (n-1) - i;
                        string currID = Convert.ToString(p) + "x" + Convert.ToString(realHeight);
                        
                        ToggleButton newBtn = new ToggleButton();
                        newBtn.SetValue(Grid.RowProperty, i);
                        newBtn.SetValue(Grid.ColumnProperty, p);
                        newBtn.Background = wBrush;
                        newBtn.Checked += ToggleButton_Click;
                        newBtn.Unchecked +=ToggleButton_UnClick;
                        
                        newBtn.Name = "_" + currID;
                        mainGrid.Children.Add(newBtn);
                        //this.RegisterName(newBtn.Name, newBtn); 
                    }
                }

                //conWindow.Show();
                tilingTools.conTextAdd("Structurizer initialized... Waiting for input.");
            };
			
		}
        private void ToggleButton_Click(object sender, RoutedEventArgs e)
        {
            SolidColorBrush lbBrush = new SolidColorBrush();
            lbBrush.Color = Color.FromArgb(255, 127, 255, 212);
            if ((sender as ToggleButton).IsChecked.Value)
            {
                // Code for Checked state
                (sender as ToggleButton).Background = lbBrush;
                // also let's add this button the the list
                listTiles = Wrapper.updateTile((sender as ToggleButton).Name, listTiles);
                tilingTools.conTextAdd("Added tile with coordinates " + (sender as ToggleButton).Name + " to list.");
                // and we'll do the same for the unclick with produceOutput.removeTile
            }
        }

        private void ToggleButton_UnClick(object sender, RoutedEventArgs e)
        {
            SolidColorBrush wBrush = new SolidColorBrush();
            wBrush.Color = Colors.White;
            if (!(sender as ToggleButton).IsChecked.Value)
            {
                // Code for unchecking state
                (sender as ToggleButton).Background = wBrush;
                listTiles = Wrapper.removeTile((sender as ToggleButton).Name, listTiles);
                tilingTools.conTextAdd("Removed tile with coordinates " + (sender as ToggleButton).Name + " to list.");
            }
        }

        private void aboutClick(object sender, RoutedEventArgs e)
		{
			MessageBox.Show("nanobox\nA CAD tool for generating self-assembling DNA structures, " +
            "by: \n\n Dr. Ming-Yang Kao \n Matthew King \n Aaron Sterling \n Curtis Wang"
			+ "\n\n Electrical Engineering and Computer Science Dept. \n McCormick School of Engineering \n Northwestern University"
            + ", Evanston, IL \n\n http://dna.eecs.northwestern.edu/");
		}
		private void exitClick(object sender, RoutedEventArgs e)
		{
            tilingTools.conTextAdd("Exiting application...");
			Application.Current.Shutdown();
		}

        private void NormalOp_Checked(object sender, RoutedEventArgs e)
        {
            tilingTools.conTextAdd("Running using basic threshold-based rectangulation.");
            opMode = 1;
        }

        private void BypassMode_Checked(object sender, RoutedEventArgs e)
        {
            tilingTools.conTextAdd("Running using automatic geometrical rectangulation.");
            opMode = 2;
        }

        private void ListMode_Checked(object sender, RoutedEventArgs e)
        {
            opMode = 3;
            MessageBox.Show("Feature not yet implemented, sorry!");
            (sender as ToggleButton).IsChecked = false;
            NormalOp.IsChecked = true;
        }

        private void clearGrid(object sender, RoutedEventArgs e)
        {
            
        }
        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {

            tilingTools.conTextAdd("Exiting application...");
            Application.Current.Shutdown();
        }

        private void genOutput(object sender, RoutedEventArgs e)
        {
            // if we have to read the drawn tiles and apply giftwrap
            if (opMode == 1)
            {
                // ask for the threshold for giftwrap
                thresholdInput thrIn = new thresholdInput();
                thrIn.Owner = this;
                thrIn.ShowDialog(); // *** NEED TO PLACE CHECK TO MAKE SURE INPUT IS GIVEN
                int threshold = Convert.ToInt32(thrIn.threshIn.Text);

                tilingTools.conTextAdd("Threshold was input as " + threshold + ".");

                // ask for the length
                lengthWindow lengthWin = new lengthWindow();
                lengthWin.Owner = this;
                lengthWin.ShowDialog();
                int lengthA = 0;
                int lengthB = 0;
                int lengthF = 0;
                if (lengthWin.autoLength.IsChecked == false)
                {
                    lengthA = Convert.ToInt32(lengthWin.lengthA.Text);
                    lengthB = Convert.ToInt32(lengthWin.lengthB.Text);
                    lengthF = Convert.ToInt32(lengthWin.lengthF.Text);
                }
                else
                    tilingTools.conTextAdd("Running using automatic length-calculation mode.");

                // Configure save file dialog box
                Microsoft.Win32.SaveFileDialog saveDlg = new Microsoft.Win32.SaveFileDialog();
                saveDlg.FileName = "structure_output"; // Default file name
                saveDlg.DefaultExt = ".html"; // Default file extension
                saveDlg.Filter = "XHTML files (*.htm, *.html)|*.html|All files (*.*)|*.*";
                saveDlg.RestoreDirectory = true;

                // Show save file dialog box
                Nullable<bool> saveChosen = saveDlg.ShowDialog();

                // Process save file dialog box results
                if (saveChosen == true)
                {
                    // Save document
                    string filepath = saveDlg.FileName;

                    // *** TODO: Open the console so we can see what's happening
                    // (12/5): We probably have to insert the bottom as a separate program, and use that window as the output console
                    

                    // produce the binary matrix and send it off to processing!
                    tilingTools.conTextAdd(">> Performing binary matrix of shape...");
                    int[,] binMatrix = Wrapper.produceBinMatrix(listTiles);
                    tilingTools.conTextAdd(">> Performing rectangulation to create tile system... ");
                    string[][] tilesWithInfo = Wrapper.produceTiles(binMatrix, threshold);
                    var result = MessageBox.Show("Please check the console for correctness before continuing, as generating glues takes a long time. Click OK to continue or Cancel to restart.", "Consistency Check", MessageBoxButton.OKCancel);
                    // cancel operation if cancel button is clicked

                    if (result == MessageBoxResult.Cancel)
                        return;
                    else
                    {
                        tilingTools.conTextAdd(">> Generating glues and producing tile report...");
                        string outputReport = produceOutput.reportWrapper(tilesWithInfo, lengthA, lengthB, lengthF);
                        try
                        {
                            File.WriteAllText(filepath, outputReport);
                        }
                        catch // !! THIS IS NOT SAFE! We need to make a write-file function or something.
                        {
                            MessageBox.Show("Error! Could not write the report. Do you have permissions to write at this location? Try saving again.");
                            saveDlg.ShowDialog();
                            filepath = saveDlg.FileName;
                            File.WriteAllText(filepath, outputReport);
                        }
                        MessageBox.Show("File saved without error at: \n" + filepath);
                        tilingTools.conTextAdd("File saved without error at: " + filepath);
                        tilingTools.conTextAdd("Opening browser window for output display...");
                        // open the report
                        Process launchReport = new Process();
                        launchReport.StartInfo = new ProcessStartInfo(filepath);
                        launchReport.Start();
                    }
                }
            }
            // matthew's automatic geometrical vertex finding
            else if (opMode == 2)
            {
                // ask for the length
                lengthWindow lengthWin = new lengthWindow();
                lengthWin.Owner = this;
                lengthWin.ShowDialog();
                int lengthA = 0;
                int lengthB = 0;
                int lengthF = 0;
                if (lengthWin.autoLength.IsChecked == false)
                {
                    lengthA = Convert.ToInt32(lengthWin.lengthA.Text);
                    lengthB = Convert.ToInt32(lengthWin.lengthB.Text);
                    lengthF = Convert.ToInt32(lengthWin.lengthF.Text);
                }
                else
                    tilingTools.conTextAdd("Running using automatic length-calculation mode.");

                // Configure save file dialog box
                Microsoft.Win32.SaveFileDialog saveDlg = new Microsoft.Win32.SaveFileDialog();
                saveDlg.FileName = "structure_output"; // Default file name
                saveDlg.DefaultExt = ".html"; // Default file extension
                saveDlg.Filter = "XHTML files (*.htm, *.html)|*.html|All files (*.*)|*.*";
                saveDlg.RestoreDirectory = true;

                // Show save file dialog box
                Nullable<bool> saveChosen = saveDlg.ShowDialog();

                // Process save file dialog box results
                if (saveChosen == true)
                {
                    // Save document
                    string filepath = saveDlg.FileName;

                    // ** TODO: background worker each UPDATE rather than the actual main worker! smart!

                    // produce the binary matrix and send it off to processing!
                    tilingTools.conTextAdd(">> Performing binary matrix of shape...");
                    int[,] binMatrix = Wrapper.produceBinMatrix(listTiles);
                    tilingTools.conTextAdd(">> Performing rectangulation to create tile system... ");
                    string[][] tilesWithInfo = Wrapper.produceAutoTiles(binMatrix);
                    var result = MessageBox.Show("Please check the console for correctness before continuing, as generating glues takes a long time. Click OK to continue or Cancel to restart.", "Consistency Check", MessageBoxButton.OKCancel);
                    // cancel operation if cancel button is clicked
                    if (result == MessageBoxResult.Cancel)
                        return;
                    else
                    {
                        tilingTools.conTextAdd(">> Generating glues and producing tile report...");
                        string outputReport = produceOutput.reportWrapper(tilesWithInfo, lengthA, lengthB, lengthF);
                        File.WriteAllText(filepath, outputReport);
                        MessageBox.Show("File saved without error at: \n" + filepath);
                        tilingTools.conTextAdd("File saved without error at: " + filepath);
                        tilingTools.conTextAdd("Opening browser window for output display...");
                        // open the report
                        Process launchReport = new Process();
                        launchReport.StartInfo = new ProcessStartInfo(filepath);
                        launchReport.Start();
                    }
                }
            }
            else if (opMode == 3)
            {
                // read the thing as a list
                string poo = vertListInput.Text;
                // let's clear all the delimiters, except for commas, and we'll replace the ')' with a semi-colon
                poo = poo.Replace(Environment.NewLine, "");
                poo = poo.Replace("(", "");
                poo = poo.Replace(')', ';');

                // cause it's easier to implement in the library, let's just send it off for processing
                //Tuple<int, int>[] vertArray = Wrapper.produceVertArray(poo);

                MessageBox.Show("poo = " + poo);
            }
         }

        private void vertListInput_Click(object sender, TextChangedEventArgs e)
        {
            vertListInput.Background = null;
        }
     }
}